#!/bin/bash -eu
#
# Copyright 2020 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# The script will:
#   * Set up a persistent disk for each Elasticsearch node:
#     * Mount the persistent disk
#     * Move Elasticsearch files to the persistent disk
#   * Update the Elasticsearch configuration files
#   * Bootstrap the node
#

source /opt/c2d/elasticsearch-utils || exit 1

readonly es_cluster_name="$(get_attribute_value "es_cluster_name")"
readonly es_nodes="$(get_attribute_value "es_nodes")"
readonly elk_logstash_nodes="$(get_attribute_value "es_logstash_nodes")"
readonly elk_kibana_nodes="$(get_attribute_value "es_kibana_nodes")"
readonly es_use_https="$(get_attribute_value "es_use_https" \
  | tr '[:upper:]' '[:lower:]')"

readonly es_password="$(get_attribute_value "es_password")"
readonly kibana_sys_password="$(get_attribute_value "kibana_sys_password")"
readonly logstash_sys_password="$(get_attribute_value "logstash_sys_password")"
readonly es_default_username="elastic"
readonly kibana_sys_username="kibana_system"
readonly logstash_sys_username="logstash_system"

readonly es_tmp_certs_folder="/tmp/certs"
readonly es_cert_folder="/etc/elasticsearch/certs"
readonly es_config_file="/etc/elasticsearch/elasticsearch.yml"
readonly es_current_node="$(hostname)"
readonly es_current_node_idx="$(hostname | awk -F '-' '{ print $NF }')"
readonly es_nodes_count="$(echo "${es_nodes}" | wc -w)"
readonly es_first_hostname="$(echo "${es_nodes}" | awk '{ print $1 }')"
readonly es_min_master_nodes="$(( es_nodes_count / 2 + 1 ))"
declare es_protocol="http"

# Calculate the desired heap size to configure in elasticsearch
readonly total_memory_kb="$(awk '/MemTotal/ { print int($2) }' /proc/meminfo)"
readonly total_memory_gb="$((total_memory_kb / 1024 / 1024))"
readonly es_heap_size_gb="$((total_memory_gb / 2))"

echo "Stopping elasticsearch"
service elasticsearch stop

# Mount and format the disk
echo "Mounting and formatting the disk"
readonly es_mount_dir=/elasticsearch
readonly es_disk_name="${es_current_node}-data"
format_and_mount_disk "${es_disk_name}" "${es_mount_dir}"

# Symlink Elasticsearch data directory to datadisk path
echo "Configuring new data directory"
rm -r /var/lib/elasticsearch
ln -s "${es_mount_dir}" /var/lib/elasticsearch
mkdir "${es_mount_dir}/data"
mkdir -p "${es_mount_dir}/config/scripts"
chown -R elasticsearch:elasticsearch "${es_mount_dir}"

# Export variables to be used in configuration files
export es_cluster_name
export es_current_node
export es_heap_size_gb
export es_min_master_nodes

# Fill in the /etc/elasticsearch/elasticsearch.yml template
echo "Configuring elasticsearch.yml"
fill_in_config_template \
  /etc/elasticsearch \
  elasticsearch.yml.template \
  elasticsearch.yml

# Fill in the /etc/default/elasticsearch template
echo "Configuring /etc/default/elasticsearch"
fill_in_config_template \
  /etc/default \
  elasticsearch.template \
  elasticsearch

echo "Create logs folder"
mkdir -p /usr/share/elasticsearch/logs
chown -R elasticsearch:elasticsearch /usr/share/elasticsearch/logs

# Build a string with all nodes in a json format
es_seed_hosts="\"${es_first_hostname}\""
if [[ "${es_nodes_count}" -gt 1 ]]; then
  es_seed_hosts="$(build_seed_hosts "${es_nodes}")"
fi

# Configure cluster discovery.
if [[ "${es_nodes_count}" -gt 1 ]]; then
  echo "Cluster-mode selected with ${es_nodes_count} nodes."

  sed -i 's\discovery.type: single-node\\g' "${es_config_file}"
  echo "discovery.seed_hosts: [ ${es_seed_hosts} ]" \
    >> "${es_config_file}"

  echo "cluster.initial_master_nodes: [ \"${es_first_hostname}\" ]" \
    >> "${es_config_file}"

  if [[ "${es_current_node}" == "${es_first_hostname}" ]]; then
    echo "node.master: true" \
      >> "${es_config_file}"
  fi
else
  echo "Single-node mode selected."
fi

# Install and configure self-signed certificates if option is selected
if [[ "${es_use_https:-"false"}" == "true" ]]; then
  es_protocol="https"
  echo "Generating certificates..."

  # If its first node, generate and share the certificate to other nodes.
  if [[ "${es_first_hostname}" == "${es_current_node}" ]]; then
    generate_certificates "${es_tmp_certs_folder}"\
      "${es_nodes}" "${elk_logstash_nodes}" "${elk_kibana_nodes}"

    # Share certificates in a non-exposed port 8000
    echo "Starting certificates sharing service..."
    systemctl start certshare

    echo "Applying certificate to the first node..."
    apply_certificate_master_node \
      "${es_tmp_certs_folder}" "${es_cert_folder}" "${es_current_node_idx}"

    echo "Inject security settings to ES config file in the first node..."
    apply_secure_config "${es_config_file}" "${es_current_node_idx}"

    echo "Certificate applied with success."
  else
    echo "Awaiting for Certshare Server be up..."
    wait_for_port "${es_first_hostname}" "8000"

    echo "Download certificates from config server..."
    download_certificates \
      "${es_cert_folder}" "${es_first_hostname}" "${es_current_node_idx}"

    echo "Inject security config to ES config file in secondary node..."
    apply_secure_config "${es_config_file}" "${es_current_node_idx}"

    echo "Security config applied with success."
  fi
else
  echo "Skipping secure transport setup."
fi

echo "Starting elasticsearch..."
service elasticsearch start
systemctl enable elasticsearch

if [[ "${es_current_node}" == "${es_first_hostname}" ]]; then
  # Await for service be up
  wait_for_port "${es_current_node}" 9200

  # Auto generate passwords for built-in users using CLI
  autogenerate_passwords "${es_protocol}"
  es_default_password="$(get_autogenerated_password elastic)"

  # Update passwords according deployment manager variables.
  # Change elastic user password.
  change_user_password "${es_current_node}" "${es_protocol}" \
    "${es_default_username}" "${es_default_password}" \
    "${es_default_username}" "${es_password}"

  # Change kibana_system user password.
  change_user_password "${es_current_node}" "${es_protocol}" \
    "${es_default_username}" "${es_password}" \
    "${kibana_sys_username}" "${kibana_sys_password}"

  # Change logstash_system user password.
  change_user_password "${es_current_node}" "${es_protocol}" \
    "${es_default_username}" "${es_password}" \
    "${logstash_sys_username}" "${logstash_sys_password}"

  # Remove passwords file
  remove_pwd_file
fi

# Await until all nodes are green
wait_for_green_elastic_cluster "${es_protocol}" "${es_current_node}" \
  "${es_nodes_count}" "${es_password}"
